#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
#include <atomic>
#include <functional>


template<class T>
class my_auto_ptr
{
private:
	T* _ptr;
	
public:
	my_auto_ptr(const T* ptr)
		:_ptr(ptr)
	{}

	my_auto_ptr(my_auto_ptr<T>& p1)
	{
		_ptr = p1._ptr;
		p1._ptr = nullptr;
	}
	
	~my_auto_ptr()
	{
		delete _ptr;
		_ptr = nullptr;
	}

	T& operator*()
	{
		return *_ptr;
	}
	T* operator&()
	{
		return &_ptr;
	}
};


template<class T>
class my_unique_ptr
{
private:
	T* _ptr;

public:
	my_unique_ptr(const T* ptr)
		:_ptr(ptr)
	{}
	my_unique_ptr(my_unique_ptr<T>& p1) = delete;
	my_unique_ptr<T>& operator=(my_unique_ptr<T>& p1) = delete;
	~my_unique_ptr()
	{
		delete _ptr;
		_ptr = nullptr;
	}

	T& operator*()
	{
		return *_ptr;
	}
	T* operator&()
	{
		return &_ptr;
	}
};


template<class T>
class DeleteArr
{
public:
	void operator()(T* ptr)
	{
		delete[] ptr;
	}
};

template<class T>
class my_shared_ptr
{
private:
	T* _ptr;
	std::atomic<int>* _pcount;

public:
	using Delete = function<void(T* ptr)>;
	Delete _del = [](T* ptr) {delete _ptr; };

	my_shared_ptr(const T* ptr)
		:_ptr(ptr)
		,_pcount(new std::atomic<int>(1))
	{}

	my_shared_ptr(const T* ptr,Delete del)
		:_ptr(ptr)
		,_pcount(new std::atomic<int>(1))
		,_del(del)
	{}
	my_shared_ptr(my_shared_ptr<T>& p1)
	{
		_ptr = p1._ptr;
		_pcount = p1._pcount;
		*(_pcount)++;
	}
	//p1 = p3 p1 = p1 p1 = p2
	my_shared_ptr<T>& operator=(my_shared_ptr<T>& p1)
	{
		if (_ptr != p1._ptr)
		{
			release();
			_ptr = p1._ptr;
			_pcount = p1._pcount;
			*(_pcount)++;
		}
		return *this;
	}
	T* get()
	{
		return _ptr;
	}
	void release()
	{
		if (--(*_pcount) == 0)
		{
			std::cout << "delete: " << _ptr << std::endl;
			_del(_ptr);
			delete _pcount;
		}
	}
	~my_shared_ptr()
	{
		release();
	}
	T& operator*()
	{
		return *_ptr;
	}
	T* operator&()
	{
		return &_ptr;
	}

};

template<class T>
class my_weak_ptr
{
private:
	T* _ptr;
public:
	my_weak_ptr()
		:_ptr(nullptr)
	{}
	my_weak_ptr(my_shared_ptr<T>& ptr)
	{
		_ptr = ptr.get();
	}
	my_weak_ptr<T>& operator=(my_shared_ptr<T>& ptr)
	{
		_ptr = ptr.get();
		return *this;
	}

	~my_weak_ptr()
	{
		;
	}

	T& operator*()
	{
		return *_ptr;
	}
	T* operator&()
	{
		return &_ptr;
	}
};